<?php

namespace plugin\ai\app\handler\driver;

use Exception;
use support\exception\BusinessException;
use Workerman\Http\Client;
use Workerman\Http\Response;

class Claude extends Base
{
    /**
     * @var string api地址
     */
    protected $api = 'https://api.anthropic.com';

    /**
     * @var float
     */
    protected $version = '2023-06-01';

    /**
     * @param $options
     */
    public function __construct($options)
    {
        parent::__construct($options);
        $this->api = $options['api'] ?? $this->api;
    }

    /**
     * @desc completions
     * @param array $data
     * @param array $options
     */
    public function completions(array $data, array $options)
    {
        $headers = $this->getHeaders($options);

        $this->api.= '/v1/messages';

        $headers['x-api-key'] = $this->apikey;
        $headers['anthropic-version'] = $this->version;

        if (isset($options['stream'])) {
            $data['stream'] = true;
        }
        if ($data['stream'] ?? false) {
            $headers['Accept'] = 'text/event-stream';
        }

        $options = $this->formatOptions($options);

        $data = static::formatData($data);

        $requestOptions = [
            'method' => 'POST',
            'data' => json_encode($data),
            'headers' => $headers,
            'progress' => function ($buffer) use ($options) {
                $data = [
                    'content' => static::formatResponse((string)$buffer),
                ];

                if (empty($data['content'])) {
                    $data = [
                        'error' => [
                            'code' => 500,
                            'message' => '网络链接错误，请稍后重试！',
                            'detail' => json_decode($buffer, true)
                        ],
                    ];
                }

                $options['stream']($data);
            },
            'success' => function (Response $response) use ($options) {
                $options['complete'](static::formatResponse((string)$response->getBody()), $response);
            },
            'error' => function ($exception) use ($options) {
                $options['complete']([
                    'error' => [
                        'code' => 'exception',
                        'message' => $exception->getMessage(),
                        'detail' => (string) $exception
                    ],
                ], new Response(0));
            }
        ];
        $http = new Client(['timeout' => 600]);
        $http->request($this->api, $requestOptions);
    }

    /**
     * 格式化消息
     * @param array $data
     * @return array
     */
    protected static function formatData(array $data)
    {
        $model = $data['model'] ?? '';
        $temperature = $data['temperature'] ?? null;
        $maxTokens = $data['max_tokens']??1024;
        $messages = static::formatMessages($data['messages']);
        $data = [
            'model'             => $model,
            'messages'          => $messages,
            'max_tokens'        => $maxTokens,
            'stop_sequences'    => array("\n\nHuman:")
        ];
        if ($temperature !== null) {
            $data['temperature'] = $temperature;
        }
        return $data;
    }

    public static function formatResponse($buffer)
    {
        $json = json_decode($buffer, true);
        if ($json) {
            if ($content = $json['content'] ?? '') {
                if (is_array($content)) {
                    foreach ($content as $value) {
                        return $value['text'];
                    }
                }
                return $content;
            }
            return $json;
        }
        foreach (array_reverse(explode("\n", $buffer)) as $chunk) {
            if (preg_match('/data:/', $chunk)) {
                $json = json_decode(substr($chunk, 5), true);
                if (!empty($json['content'])) {
                    if (is_array($json['content'])) {
                        foreach ($json['content'] as $value) {
                            return $value['text'];
                        }
                    }
                    return $json['content'];
                }
            }
        }
        return $buffer;
    }
}